home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / pc2_140.zip / SOURCE.ZIP / Source / PC2.c < prev    next >
C/C++ Source or Header  |  1993-04-17  |  73KB  |  1,276 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *                 Copyright (C) by Stangl Roman, 1993                 *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed, under the conditions indicated in the documentation.       *
  6.  *                                                                     *
  7.  * PC/2 - Program Commander/2 is a configurable program starter for    *
  8.  * OS/2 2.0 PM. If the user clicks button 1 on the DESKTOP, a user     *
  9.  * modifyable popup menu is displayed. The user then selects a program *
  10.  * to be started, or configuration of PC/2 or dismisses it.            *
  11.  * PC/2 is an alternative method of starting programs compared to      *
  12.  * icons and uses no space on DESKTOP, and no folder must be opended   *
  13.  * to start a program. For frequently used programs, this reduces the  *
  14.  * time to start an application.                                       *
  15.  *                                                                     *
  16. \***********************************************************************/
  17.  
  18. static char RCSID[]="@(#) $Header: PC2.c/PC2.h Version 1.40 04,1993 $ (LBL)";
  19.  
  20. #define         _FILE_  "PC/2 - PC2.c V1.40"
  21.  
  22. #include        "PC2.h"                 /* User include files */
  23. #include        "Error.h"
  24.  
  25.                                         /* PC/2 semaphore to avoid loading PC/2 twice */
  26. #define         PC2_SEM "\\SEM32\\PC2_SEM.SEM"
  27. #define         DESKTOP_CLASS   "#37"   /* Class name of the "Desktop" window handle (which
  28.                                            is reserved in the Toolkit */
  29.  
  30. HEV             hevPc2;                 /* Handle of PC/2 semaphore */
  31. BOOL            InstallHelp;            /* True if we're installing */
  32. UCHAR           *pucFilenameProfile;    /* The buffer holding the filename of the profile */
  33. UCHAR           *pucFilenameHLP;        /* The buffer holding the filename of the HLP file */
  34. UCHAR           *pucPathDLL;            /* Directory of PC/2 to seek for DLL file */
  35.                                         /* Default the Popup-Menu is displayed after a
  36.                                            WM_BUTTON1CLICK on the Desktop, but users may
  37.                                            prefer WM_BUTTON1DBLCLK to popup the menu */
  38. ULONG           ulClickFlag=WM_BUTTON1DBLCLK;
  39. HMODULE         hDllPc2;                /* Handle of PC/2 DLL */
  40. PFFUNCPTR1      *pPC2DLL_SetHwnd;       /* Pointer to DLL-Functions */
  41. PFFUNCPTR2      *pPC2DLL_Hook;
  42. /*                                                                                      *\
  43.  * Reserve data referenced generally through all modules. This isn't the best way, hope *
  44.  * that C++ comes out soon...                                                           *
  45. \*                                                                                      */
  46. HAB             hab;                    /* Handle of PM anchor block */
  47. HMQ             hmq;                    /* Handle of message queue */
  48. HWND            hwndFrame;              /* Frame handle of window */
  49. HWND            hwndClient;             /* Client handle of window */
  50. HWND            hwndPopupMenu;          /* Handel of popup menu window */
  51.                                         /* Input options: mouse button 1 depressed,
  52.                                            Input devices keyboard or mouse button 1,
  53.                                            popup menu allways visible on DESKTOP,
  54.                                            position so that ID_CONFIGDIALOG is under the
  55.                                            pointer */
  56. HWND            hwndHelp;               /* Help window handle */
  57. SESSIONDATA     SessionData;            /* Used by Menu Installation dialog and by
  58.                                            Program Installation dialog to store menu or
  59.                                            program data, to be filled from the user or
  60.                                            to be presented to the user. */
  61. MENUDATA        *pPopupMenu=NULL;       /* Used by all procedures as the starting point
  62.                                            of a linked list of menu entries. */
  63. MENUDATA        *pMenuData;             /* This pointer points to the current level of
  64.                                            Submenus and Menuitems within the configuration
  65.                                            dialog procedure */
  66.                                         /* Create linked list by starting with this ID */
  67. USHORT          MenuDataId=ID_POPUPMENU;
  68. USHORT          DialogResult;           /* Each dialog procedure returns the result in
  69.                                            this variable to enable the calling routine to
  70.                                            check, if there is valid data or not. */
  71. FILE            *Pc2Profile;            /* Open the profile, where the user entered menu
  72.                                            data is stored, with this handle */
  73. SWP             swpScreen;              /* The screen dimensions */
  74.  
  75. /*--------------------------------------------------------------------------------------*\
  76.  * The main procedure.                                                                  *
  77.  * Req:                                                                                 *
  78.  *      argc, argv, envp                                                                *
  79.  * Returns:                                                                             *
  80.  *      int ........... Exitcode (0, or errorlevel)                                     *
  81. \*--------------------------------------------------------------------------------------*/
  82. int main(int argc, char *argv[], char *envp[])
  83. {
  84. QMSG    qmsg;                           /* Message queue */
  85. ULONG   counter;                        /* Temporary counter */
  86.                                         /* Frame creation control flag */
  87. ULONG   flCreate=FCF_TASKLIST | FCF_ACCELTABLE;
  88.  
  89. /*                                                                                      *\
  90.  * Get the full path and filename of the running copy of PC/2 and change the extension  *
  91.  * .EXE into .cfg to open the configuration file under this name. If the user supplies  *
  92.  * [-,/Profile filename.ext] then use this filename as the Profile. Also change .EXE    *
  93.  * into .HLP and PC/2 directory as the current directory to access .DLL.                *
  94. \*                                                                                      */
  95.                                         /* Long enough to hold user Profile name */
  96. pucFilenameProfile=malloc(strlen(argv[0])+64);
  97. pucFilenameHLP=malloc(strlen(argv[0])+1);
  98. pucPathDLL=malloc(strlen(argv[0])+1);
  99. strcpy(pucFilenameProfile, argv[0]);
  100. strcpy(pucFilenameHLP, argv[0]);
  101. strcpy(pucPathDLL, argv[0]);
  102. strcpy(strchr(pucFilenameProfile, '.'), ".cfg");
  103. strcpy(strchr(pucFilenameHLP, '.'), ".hlp");
  104. strcpy(strrchr(pucPathDLL, '\\'), "");  /* Backward scan for \ */
  105. InstallHelp=FALSE;                      /* Assume no installation */
  106. for(counter=1; counter<argc; counter++)
  107.     {
  108.     strupr(argv[counter]);              /* Convert to uppercase */
  109.                                         /* Test for /PROFILE or -PROFILE to get a
  110.                                            profile name */
  111.     if((strstr(argv[counter], "/PROFILE")!=NULL) ||
  112.         (strstr(argv[counter], "-PROFILE")!=NULL))
  113.         strcpy((pucFilenameProfile+strlen(pucFilenameProfile)-7), argv[counter+1]);
  114.                                         /* Test for /INSTALL or -INSTALL to start the help
  115.                                            panels during initialization */
  116.     if((strstr(argv[counter], "/INSTALL")!=NULL) ||
  117.         (strstr(argv[counter], "-INSTALL")!=NULL))
  118.         InstallHelp=TRUE;
  119.                                         /* Test for /DOUBLECLICK or -DOUBLECLICK to display
  120.                                            the Popup-Menu after a double-click instead of
  121.                                            a single click */
  122.     if((strstr(argv[counter], "/DOUBLECLICK")!=NULL) ||
  123.         (strstr(argv[counter], "-DOUBLECLICK")!=NULL))
  124.         ulClickFlag=WM_BUTTON1DBLCLK;
  125.                                         /* Test for /SINGLECLICK or -SINGLECLICK to display
  126.                                            the Popup-Menu after a double-click instead of
  127.                                            a single click */
  128.     if((strstr(argv[counter], "/SINGLECLICK")!=NULL) ||
  129.         (strstr(argv[counter], "-SINGLECLICK")!=NULL))
  130.         ulClickFlag=WM_BUTTON1CLICK;
  131.     }
  132. do
  133. {
  134.                                         /* Initialize anchor block and message queue */
  135.     if(WinStartUp(&hab, &hmq)==FALSE) break;
  136.     if(!WinRegisterClass(               /* Register window class */
  137.         hab,                            /* Handle of anchor block */
  138.         (PSZ)PC2_CLASSNAME,             /* Window class name */
  139.         (PFNWP)PC2_MainWindowProc,      /* Address of window procedure */
  140.         CS_SAVEBITS,                    /* Class style */
  141.         0))                             /* Extra window words */
  142.         {
  143.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  144.         break;
  145.         }
  146.     if((hwndFrame=WinCreateStdWindow(   /* Create a standart window */
  147.         HWND_DESKTOP,                   /* DESKTOP is parent */
  148.         0,                              /* Standard window styles */
  149.         &flCreate,                      /* Frame control flags */
  150.         (PSZ)PC2_CLASSNAME,             /* Client window class name */
  151.         "",                             /* No window text */
  152.         0,                              /* No special class style */
  153.         (HMODULE)0,                     /* Ressource is in .EXE file */
  154.         ID_PC2MAINWINDOW,               /* Frame window identifier */
  155.         &hwndClient)                    /* Client window handle */
  156.         )==NULLHANDLE)
  157.         {
  158.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  159.         break;
  160.         }
  161. /*                                                                                      *\
  162.  * Check if we are allready loaded before by querying a semaphore that is defined the   *
  163.  * first time PC/2 runs.                                                                *
  164. \*                                                                                      */
  165.     if(DosCreateEventSem(               /* Create a semaphore */
  166.         PC2_SEM,                        /* Name */
  167.         &hevPc2,                        /* Handle */
  168.         (ULONG)0,                       /* Named semaphores are allways shared */
  169.         (BOOL32)FALSE))                 /* Initially set */
  170.         {                               /* If an error occurs, either we can't create
  171.                                            the semaphore or it allready exists. We assume
  172.                                            that it exists, meaning PC/2 allready loaded */
  173.         USR_ERR("PC/2 allready loaded - exiting...", hwndFrame, hwndClient);
  174.         break;
  175.         }
  176. /*                                                                                      *\
  177.  * Load the Pc2Hook DLL either from the current directory or a LIBPATH path and         *
  178.  * obtain the addresses of the entrypoints. There seems to be a little bug?, when the   *
  179.  * library name contains a .DLL extension - the DLL is loaded sucessfully but not       *
  180.  * always correct initialized? and calling functions in the DLL tend to fail. Extension *
  181.  * .DLL therefore not appended to library name.                                         *
  182. \*                                                                                      */
  183.     {
  184.     UCHAR       ucDrive;
  185.     UCHAR       ucBuffer[80];
  186.                                         /* Get drive of PC/2's startup directory
  187.                                            1=A, 2=B, 3=C,.... and direcotry itself */
  188.     ucDrive=tolower(pucPathDLL[0]);
  189.     DosSetDefaultDisk(++ucDrive-'a');
  190.     DosSetCurrentDir(pucPathDLL);
  191.     if(DosLoadModule(                   /* Load the DLL of PC/2 */
  192.         ucBuffer,                       /* Save failure there */
  193.         sizeof(ucBuffer)-1,             /* Length of save area */
  194.         "PC2Hook",                      /* Library name */
  195.         &hDllPc2)!=NO_ERROR)            /* DLL module handle */
  196.         {                               /* DLL couldn't be found in the current PC/2
  197.                                            directory or via the LIBPATH path */
  198.         USR_ERR("Can't find PC2HOOK.DLL, please check DLL file and LIBPATH - exiting...",
  199.             hwndFrame, hwndClient);
  200.         break;
  201.         }
  202.     if(DosQueryProcAddr(                /* Now get the address of the functions within the DLL */
  203.         hDllPc2,                        /* DLL module handle */
  204.         1,                              /* Ordinal number of procedure whose address is desired */
  205.         "PC2DLL_SetHwnd",               /* Procedure name being referenced */
  206.                                         /* Procedure address returned */
  207.         (PFN *)(&pPC2DLL_SetHwnd))!=NO_ERROR)
  208.         {                               /* An error occured */
  209.         DosFreeModule(hDllPc2);         /* Free DLL reference */
  210.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  211.         break;
  212.         }
  213.     if(DosQueryProcAddr(
  214.         hDllPc2,
  215.         2,
  216.         "PC2DLL_Hook",
  217.         (PFN *)(&pPC2DLL_Hook))!=NO_ERROR)
  218.         {
  219.         DosFreeModule(hDllPc2);
  220.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  221.         break;
  222.         }
  223.     }
  224. /*                                                                                      *\
  225.  * Now initilize Help, if it can't be initialized the we get no help but that's no      *
  226.  * reason to terminate.                                                                 *
  227. \*                                                                                      */
  228.     if(WinStartHelp(hab, pucFilenameHLP, &hwndHelp)==FALSE)
  229.         USR_ERR("Can't find PC2.HLP, please check HLP file and HELP - ignoring help requests...",
  230.             hwndFrame, hwndClient);
  231.                                         /* Query and save the device resolution */
  232.     swpScreen.cx=WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  233.     swpScreen.cy=WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  234.     if(!WinSetWindowPos(                /* Set window postion */
  235.         hwndFrame,                      /* Window handle */
  236.         HWND_BOTTOM,                    /* Window position at background */
  237.         0, 0, 0, 0,                     /* Window size */
  238.                                         /* Window control */
  239.         SWP_ZORDER | SWP_SHOW | SWP_DEACTIVATE))
  240.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  241.     WinSetWindowText(hwndFrame, "PC/2 - Program Commander/2");
  242. /*                                                                                      *\
  243.  * Now setup the Popup-Menu by loading the data from the profile and install the hook   *
  244.  * into the system input queue.                                                         *
  245. \*                                                                                      */
  246.     hwndPopupMenu=WinLoadMenu(          /* Load popup menu */
  247.         hwndClient,                     /* Owner window handle */
  248.         (HMODULE)0,                     /* Ressource in .EXE file */
  249.         ID_PC2MAINWINDOW);              /* Menu identifier in ressource file */
  250.                                         /* Load the data from the profile */
  251.     WinPostMsg(hwndClient, WM_SETPOPUPMENU, NULL, NULL);
  252.                                         /* Now install the hook */
  253.     WinPostMsg(hwndClient, WM_LOADHOOK, NULL, NULL);
  254. /*                                                                                      *\
  255.  * Here we loop dispatching the messages...                                             *
  256. \*                                                                                      */
  257.     while(WinGetMsg(hab, &qmsg, 0, 0, 0))
  258.         WinDispatchMsg(hab, &qmsg);     /* Dispatch messages to window procedure */
  259.     WinDestroyWindow(hwndFrame);        /* Close window */
  260. } while (FALSE);
  261.  
  262. if(WinCloseDown(&hwndHelp, &hab, &hmq)==FALSE) return(1);
  263. else return(0);
  264. }
  265.  
  266. /*--------------------------------------------------------------------------------------*\
  267.  * This procedure is the PC/2 window procedure.                                         *
  268. \*--------------------------------------------------------------------------------------*/
  269. MRESULT EXPENTRY PC2_MainWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  270. {
  271. switch(msg)
  272. {
  273. case WM_CREATE:                         /* Create window by WinCreateStdWindow() */
  274.     {
  275.     USHORT      usTimer;
  276.                                         /* First call default window procedure */
  277.     WinDefWindowProc(hwnd, msg, mp1, mp2);
  278.     if(InstallHelp==TRUE)               /* For installation display help panels */
  279.         WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(ID_HELP), NULL);
  280.                                         /* Start timer for WM_TIMER every 2,5 seconds */
  281.     for(usTimer=0; usTimer<=TID_USERMAX; usTimer++)
  282.                                         /* If we found the first timer break */
  283.         if(WinStartTimer(hab, hwnd, usTimer, 02500)) break;
  284.     if(usTimer>TID_USERMAX)             /* Inform user if we can't find a timer */
  285.         USR_ERR("Cannot obtain a timer", hwndFrame, hwndClient);
  286.     }
  287.     break;
  288.  
  289. /*                                                                                      *\
  290.  * Syntax: WM_SETPOPUPMENU, NULL, NULL                                                  *
  291. \*                                                                                      */
  292. case WM_SETPOPUPMENU:
  293. /*                                                                                      *\
  294.  * Open the profile for reading the linked list containing the popup menu data. If the  *
  295.  * profile can't be opened, the file is assumed to be empty so the popup menu is empty. *
  296. \*                                                                                      */
  297.     if((Pc2Profile=fopen(pucFilenameProfile, "r"))==NULL)
  298.         {
  299.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  300.                                            the first element of linked list */
  301.         USR_ERR("Cannot open confguration file - assuming empty file", hwndFrame, hwndClient);
  302.         }
  303.     else
  304.         {
  305.         static UCHAR    Buffer[256];
  306.  
  307.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  308.                                            the first element of linked list */
  309.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  310.         if(strcmp(Buffer, "PROFILE START\n")==0)
  311.             LoadMenu(pPopupMenu);       /* Load the rest by calling a recursive procedure */
  312.         fclose(Pc2Profile);
  313.         }
  314.     pMenuData=pPopupMenu;               /* Initialize *MENUDATA for Configuration dialog
  315.                                            procedure to a known value */
  316.     break;
  317.  
  318. case WM_TIMER:
  319. /*                                                                                      *\
  320.  * If we run without the WPS, the user may decide to start PMSHELL sometimes. If he     *
  321.  * does this, the window handle of the Desktop, where we catch the mouse button clicks  *
  322.  * changes. So we use the timer on a regular basis of about 1 second the query for the  *
  323.  * window handle to see any changes immediately.                                        *
  324. \*                                                                                      */
  325. /*                                                                                      *\
  326.  * Syntax: WM_SETDESKTOPHANDLE, NULL, NULL                                              *
  327. \*                                                                                      */
  328. case WM_SETDESKTOPHANDLE:
  329. /*                                                                                      *\
  330.  * Query the window handle of the Desktop window and load it into PC2HOOK.DLL library.  *
  331. \*                                                                                      */
  332.     {
  333.     UCHAR       ucClass[33];            /* Save class name here */
  334.     HWND        hwndDesktop;            /* Save "Desktop" window handle, where the user
  335.                                            clicks with mouse button 1 */
  336.     HENUM       henumWindows;           /* Enumerate windows */
  337.     BOOL        bMatch;                 /* True if correct "Desktop" window handle was found */
  338.  
  339.                                         /* Get to bottommost window handle of the "Desktop" */
  340.     hwndDesktop=WinQueryWindow(HWND_DESKTOP, QW_BOTTOM);
  341.                                         /* Enumerate all windows at "Desktop" z-order */
  342.     henumWindows=WinBeginEnumWindows(hwndDesktop);
  343.     bMatch=FALSE;
  344.     while(hwndDesktop=WinGetNextWindow(henumWindows))
  345.         {
  346.                                         /* Now get the class name of that window handle */
  347.         WinQueryClassName(hwndDesktop, sizeof(ucClass)-1, (PCH)ucClass);
  348.                                         /* If we find the required "Desktop" window (it
  349.                                            has a class name of #37, which is reserved in the
  350.                                            Toolkit) set this value into the Hook DLL */
  351.         if(!strcmp(ucClass, DESKTOP_CLASS))
  352.             {
  353.             bMatch=TRUE;
  354.             pPC2DLL_SetHwnd(ulClickFlag, hwndDesktop, hwnd);
  355.             }
  356.         }
  357.     WinEndEnumWindows(henumWindows);    /* End enumeration */
  358. /*                                                                                      *\
  359.  * If bMatch==TRUE then we have found the required "Desktop" window, but this is only   *
  360.  * available if the WPS is running. If the WPS is not running (PM running alone, then   *
  361.  * bMatch==FALSE will be set. Thus bMatch will be used to differentiate between PM      *
  362.  * running with WPS and without WPS - however I don't know if this holds true for all   *
  363.  * OS/2 2.x releases.                                                                   *
  364. \*                                                                                      */
  365.     if(bMatch==FALSE)
  366.         {
  367.                                         /* Without WPS installed we can get the "Desktop"
  368.                                            window handle easily */
  369.         hwndDesktop=WinQueryDesktopWindow(hab, NULLHANDLE);
  370.         pPC2DLL_SetHwnd(ulClickFlag, hwndDesktop, hwnd);
  371.         }
  372.     }
  373.     break;
  374.  
  375. /*                                                                                      *\
  376.  * Syntax: WM_LOADHOOK, NULL, NULL                                                      *
  377. \*                                                                                      */
  378. case WM_LOADHOOK:
  379. /*                                                                                      *\
  380.  * Install the hook into the system input queue pointing to the PC2DLL_Hook() procedure *
  381.  * in the DLL PC2HOOK.DLL. If we can't do this we exit after an error message box.      *
  382. \*                                                                                      */
  383.                                         /* Query and set the window handle of the Desktop */
  384.     WinSendMsg(hwnd, WM_SETDESKTOPHANDLE, NULL, NULL);
  385.     if(WinSetHook(                      /* Set a hook */
  386.         hab,                            /* Handle of anchor block */
  387.         NULLHANDLE,                     /* Hook into system message queue */
  388.         HK_INPUT,                       /* Hook of system input queue */
  389.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  390.         hDllPc2)==FALSE)
  391.         {
  392.         USR_ERR("Hooking the system input queue failed - exiting...", hwndFrame, hwndClient);
  393.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  394.         }
  395.     break;
  396.  
  397. /*                                                                                      *\
  398.  * Syntax: WM_POPUPMENU, (x,y), mp2                                                     *
  399. \*                                                                                      */
  400. case WM_POPUPMENU:
  401. /*                                                                                      *\
  402.  * The hook found that button 1 was clicked on the Desktop and sent us this message. It *
  403.  * is either a WM_BUTTON1CLICK or WM_BUTTON1DBLCLK. First we obtain the focus, to be    *
  404.  * able to start our programs in the foreground.                                        *
  405. \*                                                                                      */
  406.     {
  407.     USHORT      fsOptions=PU_NONE | PU_KEYBOARD | PU_MOUSEBUTTON1 |
  408.                           PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN;
  409.  
  410.     WinSetFocus(HWND_DESKTOP, hwnd);    /* Set focus to our window */
  411.     if(!WinPopupMenu(                   /* Pop up the popup menu */
  412.         HWND_DESKTOP,                   /* Parent window handle */
  413.         hwnd,                           /* Owner window handle that receives all the
  414.                                            notification messages generated by the pop-up
  415.                                            menu */
  416.         hwndPopupMenu,                  /* Popup menu window handle */
  417.         SHORT1FROMMP(mp1),              /* x-coordinate of mouse pointer for popup menu */
  418.         SHORT2FROMMP(mp1),              /* y-coordinate of mouse pointer for popup menu */
  419.         ID_PC2SETUP,                    /* Input item identity, if PU_POSITIONONITEM or
  420.                                            PU_SELECTITEM is set */
  421.         fsOptions)                      /* Input options */
  422.     ) GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  423.     break;
  424.     }
  425.  
  426. case WM_CLOSE:
  427.     if(WinMessageBox(                   /* Ask the user if he really wants to exit */
  428.         HWND_DESKTOP, HWND_DESKTOP,
  429.         "Are you sure you want to close PC/2?",
  430.         "PC/2 - Program Commander/2",
  431.         ID_PC2MAINWINDOW,
  432.         MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK)
  433.         return((MRESULT)TRUE);          /* Only exit if OK is pressed */
  434.     if(WinReleaseHook(                  /* Release hook */
  435.         hab,                            /* Handle  of anchor block */
  436.         NULLHANDLE,                     /* Release from system hook chain */
  437.         HK_INPUT,                       /* Hook of system input queue */
  438.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  439.         hDllPc2)==FALSE)
  440.         {
  441.         USR_ERR("Unhooking the system input queue failed, System ShutDown suggested - exiting...",
  442.             hwndFrame, hwndClient);
  443.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  444.         }
  445.     DosFreeModule(hDllPc2);             /* Free DLL reference */
  446.     WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  447.     break;
  448.  
  449. case HM_ERROR:
  450.    {
  451.    GEN_ERR(hab, hwndFrame, hwndClient);
  452.    break;
  453.    }
  454.  
  455. case WM_COMMAND:
  456.     {
  457.     USHORT      command;
  458.  
  459.     command=SHORT1FROMMP(mp1);          /* Extract the command value */
  460. /*                                                                                      *\
  461.  * Filter the IDs of the user defined items of the Popup-Menu. If one is found, call    *
  462.  * SearchItem() to search for the corresponding MENUDATA structure, copy it to a        *
  463.  * SESSIONDATA structure and start the session.                                         *
  464. \*                                                                                      */
  465.     if((command>=USERITEMFIRST) && (command<=USERITEMLAST))
  466.         {
  467.         ULONG           id=(ULONG)command;
  468.         MENUDATA        *pMD=NULL;
  469.  
  470.                                         /* Search in the linked list for this entry */
  471.         if((pMD=SearchItem(pPopupMenu, &id))!=NULL)
  472.         if(pMD->Item==ENTRYMENUITEM)
  473.             {
  474.                                         /* Load SessionData with MENUDATA structure */
  475.             LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  476.                                         /* Start the session */
  477.             StartSession(&SessionData);
  478.             }
  479.         }
  480.     switch(command)
  481.     {
  482.  
  483.     case ID_HELP:                       /* Display general help panel */
  484.         if(hwndHelp!=NULLHANDLE) WinSendMsg(
  485.             hwndHelp,                   /* Help window */
  486.             HM_DISPLAY_HELP,            /* Display a help panel */
  487.             MPFROMSHORT(ID_HELP),       /* Panel ID in ressource file */
  488.             HM_RESOURCEID);             /* MP1 points to the help window identity */
  489.         break;
  490.  
  491.     case ID_CONFIGDIALOG:               /* Popup menuitem Configure PC/2 selected */
  492.         if(!WinDlgBox(                  /* Start Configure PC/2 dialog box */
  493.             HWND_DESKTOP,               /* DESKTOP is parent */
  494.             HWND_DESKTOP,               /* DESKTOP is owner */
  495.             CD_DialogProcedure,         /* Dialog procedure of Program Installation
  496.                                            dialog */
  497.             0,                          /* Ressource is .EXE file */
  498.             CDID_CONFIGDIALOG,          /* ID of Configure PC/2 dialog */
  499.             0))                         /* No initialization data */
  500.         GEN_ERR(hab, hwndFrame, hwndClient);
  501.         break;
  502.  
  503.     case ID_SHUTDOWN:                   /* ShutDown OS/2 menuitem selected */
  504.         if(WinMessageBox(               /* Ask the user if he really wants to shut down OS/2 */
  505.         HWND_DESKTOP, HWND_DESKTOP,
  506.         "Are you really sure you want to ShutDown OS/2?",
  507.         "PC/2 - Program Commander/2",
  508.         ID_PC2MAINWINDOW,
  509.         MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK)
  510.         return((MRESULT)TRUE);          /* Only shut down if OK is pressed */
  511.         if(!WinDlgBox(                  /* Start ShutDown OS/2 dialog box */
  512.             HWND_DESKTOP, HWND_DESKTOP, SD_DialogProcedure, 0,
  513.             SDID_SHUTDOWNDIALOG, 0))
  514.         GEN_ERR(hab, hwndFrame, hwndClient);
  515.         break;
  516.  
  517.     case ID_EXIT:                       /* User selected F3 to shutdown PC/2 */
  518.         WinPostMsg(hwnd, WM_CLOSE, 0, 0);
  519.         break;
  520.  
  521.     case ID_ABOUTDIALOG:                /* User selected About PC/2 dialog */
  522.         if(!WinDlgBox(                  /* Start About PC/2 dialog box */
  523.             HWND_DESKTOP,               /* DESKTOP is parent */
  524.             HWND_DESKTOP,               /* DESKTOP is owner */
  525.             AD_DialogProcedure,         /* Dialog procedure of Program Installation
  526.                                            dialog */
  527.             0,                          /* Ressource is .EXE file */
  528.             ADID_ABOUTDIALOG,           /* ID of Program Installation dialog */
  529.             0))                         /* No initialization data */
  530.             GEN_ERR(hab, hwndFrame, hwndClient);
  531.         break;
  532.     }
  533.     break;
  534.     }
  535.  
  536. default:                                /* Default window procedure must be called */
  537.     return((MRESULT)WinDefWindowProc(hwnd, msg, mp1, mp2));
  538. }
  539. return((MRESULT)FALSE);                 /* We have handled the message */
  540. }
  541.  
  542. /*--------------------------------------------------------------------------------------*\
  543.  * This dialog procedure handles the PC/2 - Configuration (Setup) dialog.               *
  544.  * Req: none                                                                            *
  545. \*--------------------------------------------------------------------------------------*/
  546. MRESULT  EXPENTRY CD_DialogProcedure(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  547. {
  548. switch(msg)
  549. {
  550. case WM_INITDLG:
  551.     {
  552.     SWP         swp;
  553.  
  554.     WinQueryWindowPos(                  /* Query position of dialog window */
  555.         hwndDlg,                        /* Handle of dialog window */
  556.         &swp);                          /* Fill with position */
  557.     WinSetWindowPos(                    /* Set dialog window position */
  558.         hwndDlg,                        /* Handle of dialog window */
  559.         HWND_TOP,                       /* Position on top and center of DESKTOP */
  560.         (swpScreen.cx-swp.cx)/2,
  561.         (swpScreen.cy-swp.cy)/2,
  562.         0,
  563.         0,
  564.         SWP_MOVE);
  565.                                         /* Initialize the listbox */
  566.     WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  567.     break;
  568.     }
  569.  
  570. /*                                                                                      *\
  571.  * Syntax: WM_LOADPOPUPMENU, *MENUDATA, NULL                                            *
  572. \*                                                                                      */
  573. case WM_LOADPOPUPMENU:                  /* Load the current level of the Popup-Menu in
  574.                                            the listbox after removing the old items */
  575.     {
  576.     MENUDATA    *pMD;
  577.  
  578.     pMD=PVOIDFROMMP(mp1);               /* Get the pointer to the first MENUDATA of the
  579.                                            current level */
  580.     WinSendDlgItemMsg(                  /* Send message to listbox */
  581.         hwndDlg,                        /* Handle of dialog window */
  582.         CDLB_MENUPROGRAM,               /* Submenu & Program listbox */
  583.         LM_DELETEALL,                   /* Delete all list box items */
  584.         (MPARAM)NULL,
  585.         (MPARAM)NULL);
  586.     if(pMD==NULL) break;                /* If linked list is empty break out */
  587.     do
  588.     {
  589.         if(pMD->Item==ENTRYSUBMENU)     /* It is a Submenu */
  590.             {
  591.             UCHAR       Buffer[EF_SIZE60+4];
  592.                                         /* Add >> for a Submenu */
  593.             sprintf(Buffer, "%s >>", pMD->PgmTitle);
  594.             WinSendDlgItemMsg(
  595.                 hwndDlg,
  596.                 CDLB_MENUPROGRAM,
  597.                 LM_INSERTITEM,          /* Insert Submenu Title at the end */
  598.                 MPFROMSHORT(LIT_END),
  599.                 MPFROMP(Buffer));
  600.             }
  601.         if(pMD->Item==ENTRYMENUITEM)    /* It's a Menuitem */
  602.             WinSendDlgItemMsg(
  603.                 hwndDlg,
  604.                 CDLB_MENUPROGRAM,
  605.                 LM_INSERTITEM,          /* Insert Menuitem Title at the end */
  606.                 MPFROMSHORT(LIT_END),
  607.                 MPFROMP(pMD->PgmTitle));
  608.                                         /* It may also be an empty entry, but then we
  609.                                            ignore it, because it must be filled with
  610.                                            Menuitem or Submenu data first */
  611.         if(pMD->Next!=NULL)             /* Get through linked list without diving into
  612.                                            Submenus */
  613.                 pMD=pMD->Next;
  614.         else break;                     /* We're at the end of the linked list */
  615.     }while(TRUE);
  616.     break;
  617.     }
  618.  
  619. /*                                                                                      *\
  620.  * Syntax: WM_SAVEPOPUPMENU, NULL, NULL                                                 *
  621. \*                                                                                      */
  622. case WM_SAVEPOPUPMENU:                  /* Save the Popup-Menu to the configuraion file */
  623.     if((Pc2Profile=fopen(pucFilenameProfile, "w"))==NULL)
  624.         USR_ERR("Cannot open confguration file - changes won't be saved",
  625.                 hwndFrame, hwndClient);
  626.     else
  627.         {
  628.         fprintf(Pc2Profile, "PROFILE START\n");
  629.         SaveMenu(pPopupMenu);           /* Save the menu linked list */
  630.         fprintf(Pc2Profile, "PROFILE END\n");
  631.         fclose(Pc2Profile);
  632.         }
  633.     break;
  634.  
  635. case WM_HELP:                           /* Help pressed */
  636.     WinSendMsg(
  637.         hwndHelp,                       /* Help window */
  638.         HM_DISPLAY_HELP,                /* Display a help panel */
  639.         MPFROMSHORT(ID_CONFIGDIALOG),   /* Panel ID in ressource file */
  640.         HM_RESOURCEID);                 /* MP1 points to the help window identity */
  641.     break;
  642.  
  643. case WM_COMMAND:                        /* Button pressed */
  644.     switch(SHORT1FROMMP(mp1))
  645.     {
  646. /*                                                                                      *\
  647.  * Chain up the linked list until we find the node, where this part-list comes from or  *
  648.  * the beginning of the complete list. The pointer pMenuData is adjusted.               *
  649. \*                                                                                      */
  650.     case CDID_LEVELUP:                  /* Get up one level in the linked list */
  651.         {
  652.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  653.                                            Submenu where this part-list starts */
  654.  
  655.         pMD=pMenuData;                  /* Point to the first element of the linked list
  656.                                            at the current level */
  657.         if(pMD->Back==NULL)             /* If we're at the beginning of the complete linked
  658.                                            list ignore button */
  659.             return((MRESULT)FALSE);
  660.         else pMD=pMD->Back;             /* Submenu which started current level */
  661.                                         /* Now chain back through the linked list and find
  662.                                            the element, where the pointer to a Submenu
  663.                                            equals the back pointer of the first element
  664.                                            in this Submenu. Then we've found the node */
  665.         while(TRUE)
  666.             {
  667.             if(pMD->Back==NULL)         /* If we're now at the beginning break */
  668.                 break;
  669.             if((pMD->Back)->Submenu==pMD)
  670.                 break;
  671.             else pMD=pMD->Back;
  672.             }
  673.         pMenuData=pMD;                  /* Load as the top element of the current item */
  674.                                         /* Now redraw items in listbox */
  675.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  676.         return((MRESULT)FALSE);         /* We handled this button */
  677.         }
  678.  
  679. /*                                                                                      *\
  680.  * Test the user selection for being a Submenu. If one found chain into this submenu    *
  681.  * and adjust the pointer pMenuData.                                                    *
  682. \*                                                                                      */
  683.     case CDID_LEVELDOWN:                /* Get down one level in the linked list */
  684.         {
  685.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  686.                                            Submenu to chain into */
  687.         SHORT           sCount;
  688.  
  689.         pMD=pMenuData;                  /* Point to the first element of the linked list
  690.                                            at the current level */
  691.                                         /* Send message to listbox */
  692.         sCount=(SHORT)WinSendDlgItemMsg(
  693.             hwndDlg,                    /* Handle of dialog window */
  694.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  695.             LM_QUERYSELECTION,          /* Query first selected list box item */
  696.             MPFROMSHORT(LIT_FIRST),
  697.             (MPARAM)NULL);
  698.                                         /* If no item selected, ignore this button */
  699.         if(sCount==LIT_NONE)
  700.             return((MRESULT)FALSE);
  701.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  702.                                            item */
  703.             pMD=pMD->Next;
  704.         if(pMD->Item!=ENTRYSUBMENU)     /* It's not a Submenu that's selected, ignore */
  705.             return((MRESULT)FALSE);
  706.         pMenuData=pMD->Submenu;         /* Otherwise chain into this part-list */
  707.                                         /* Now redraw items in listbox */
  708.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  709.         return((MRESULT)FALSE);         /* We handled this button */
  710.         }
  711.  
  712. /*                                                                                      *\
  713.  * The user selected to add a (Sub)Menu. Thus dismiss the PC/2 Configuration dialog and *
  714.  * load the (Sub)Menu Installation dialog. The new (Sub)Menu is entered in a            *
  715.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  716.  * Configuration dialog again.                                                          *
  717. \*                                                                                      */
  718.     case CDID_ADDMENU:                  /* Add a Menu to PC/2 Configuration selected */
  719. /*                                                                                      *\
  720.  * The user selected to add a Program. Thus dismiss the PC/2 Configuration dialog and   *
  721.  * load the Program Installation dialog. The new session data is entered in a           *
  722.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  723.  * Configuration dialog again.                                                          *
  724. \*                                                                                      */
  725.     case CDID_ADDPROGRAM:               /* Add a Program to PC/2 Configuration selected */
  726.         {
  727.         UCHAR           *pU;            /* Temporary character pointer */
  728.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to insert a
  729.                                            new MENUDATA stucture after */
  730.         MENUDATA        *pMDNew;        /* Temporary pointer for the new item to be inserted
  731.                                            after pMD */
  732.         SHORT           sCount;
  733.  
  734.         pMD=pMenuData;                  /* Point to the first element of the linked list
  735.                                            at the current level */
  736.                                         /* Send message to listbox */
  737.         sCount=(SHORT)WinSendDlgItemMsg(
  738.             hwndDlg,                    /* Handle of dialog window */
  739.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  740.             LM_QUERYSELECTION,          /* Query first selected list box item */
  741.             MPFROMSHORT(LIT_FIRST),
  742.             (MPARAM)NULL);
  743.                                         /* If no item selected, and there exists one,
  744.                                            add the new Menuitem after the last available
  745.                                            Menuitem by querying the number from the listbox.
  746.                                            Subtract 0 because we use 0-based instead 1-based. */
  747.         if((sCount==LIT_NONE) && (pMenuData->Item!=ENTRYEMPTY))
  748.             sCount=(SHORT)WinSendDlgItemMsg(hwndDlg, CDLB_MENUPROGRAM, LM_QUERYITEMCOUNT,
  749.                 MPFROM2SHORT(NULL, NULL), (MPARAM)NULL)-1;
  750.  
  751.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  752.                                            item */
  753.             pMD=pMD->Next;
  754.                                         /* Allocate a new item */
  755.         pMDNew=AllocateMenuData();
  756.         strcpy(pU=malloc(strlen("Insert here please")+1), "Insert here please");
  757.         free(pMDNew->PgmTitle);
  758.         pMDNew->PgmTitle=pU;
  759.         pMDNew->id=MenuDataId++;        /* Increment ID */
  760.                                         /* Load SessionData with empty pMDNew structure */
  761.         LoadMenuData2SessionData(TRUE, pMDNew, &SessionData);
  762.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  763.         if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  764.             {
  765.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  766.                 HWND_DESKTOP,           /* DESKTOP is parent */
  767.                 HWND_DESKTOP,           /* DESKTOP is owner */
  768.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  769.                                            dialog */
  770.                 0,                      /* Ressource is .EXE file */
  771.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  772.                 0))                     /* No initialization data */
  773.                 GEN_ERR(hab, hwndFrame, hwndClient);
  774.             }
  775.         else
  776.             {
  777.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  778.                 HWND_DESKTOP,           /* DESKTOP is parent */
  779.                 HWND_DESKTOP,           /* DESKTOP is owner */
  780.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  781.                                            dialog */
  782.                 0,                      /* Ressource is .EXE file */
  783.                 PIID_PROGRAMDIALOG,     /* ID of Addprogram PC/2 dialog */
  784.                 0))                     /* No initialization data */
  785.                 GEN_ERR(hab, hwndFrame, hwndClient);
  786.             }
  787.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  788.                                            the SESSIONDATA structure back to the MENUDATA
  789.                                            structure and save the changes */
  790.             {
  791.             LoadSessionData2MenuData(pMDNew, &SessionData);
  792.             if(pMD->Item!=ENTRYEMPTY)   /* Add new entry, if the current entry isn't empty */
  793.                 {
  794.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  795.                     {                   /* It it is a Submenu, we also must add an empty
  796.                                            first item for it */
  797.                     MENUDATA    *pMDTemp;
  798.  
  799.                     pMDTemp=AllocateMenuData();
  800.                     pMDNew->Submenu=pMDTemp;
  801.                     pMDTemp->Back=pMDNew;
  802.                     pMDNew->Item=ENTRYSUBMENU;
  803.                     }
  804.                 else pMDNew->Item=ENTRYMENUITEM;
  805.                 if(pMD->Next!=NULL) (pMD->Next)->Back=pMDNew;
  806.                 pMDNew->Next=pMD->Next;
  807.                 pMDNew->Back=pMD;
  808.                 pMD->Next=pMDNew;
  809.                                         /* Insert item after the existing item */
  810.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDNew), MPFROMLONG(pMD->id));
  811.                 }
  812.             else                        /* If it is an empty entry fill it with user data */
  813.                 {
  814.                 UCHAR   *pU;            /* Temporary character pointer */
  815.  
  816.                 pMD->id=pMDNew->id;
  817.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  818.                     {                   /* It it is a Submenu, we also must add an empty
  819.                                            first item for it */
  820.                     MENUDATA    *pMDTemp;
  821.  
  822.                     pMDTemp=AllocateMenuData();
  823.                     pMD->Submenu=pMDTemp;
  824.                     pMDTemp->Back=pMD;
  825.                     pMD->Item=ENTRYSUBMENU;
  826.                     }
  827.                 else pMD->Item=ENTRYMENUITEM;
  828.                 strcpy(pU=malloc(strlen(pMDNew->PgmTitle)+1), pMDNew->PgmTitle);
  829.                 free(pMD->PgmTitle);
  830.                 pMD->PgmTitle=pU;
  831.                 strcpy(pU=malloc(strlen(pMDNew->PgmName)+1), pMDNew->PgmName);
  832.                 free(pMD->PgmName);
  833.                 pMD->PgmName=pU;
  834.                 strcpy(pU=malloc(strlen(pMDNew->PgmDirectory)+1), pMDNew->PgmDirectory);
  835.                 free(pMD->PgmDirectory);
  836.                 pMD->PgmDirectory=pU;
  837.                 strcpy(pU=malloc(strlen(pMDNew->PgmInputs)+1), pMDNew->PgmInputs);
  838.                 free(pMD->PgmInputs);
  839.                 pMD->PgmInputs=pU;
  840.                 pMD->SessionType=pMDNew->SessionType;
  841.                 pMD->PgmControl=pMDNew->PgmControl;
  842.                 pMD->FgBg=pMDNew->FgBg;
  843.                 pMD->InitXPos=pMDNew->InitXPos;
  844.                 pMD->InitYPos=pMDNew->InitYPos;
  845.                 pMD->InitXSize=pMDNew->InitXSize;
  846.                 pMD->InitYSize=pMDNew->InitYSize;
  847.                 pMD->PriorityClass=pMDNew->PriorityClass;
  848.                 pMD->PriorityDelta=pMDNew->PriorityDelta;
  849.                 if(pMD->Back!=NULL)     /* This is the first item of a Submenu, then
  850.                                            insert it there */
  851.                     SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMD), MPFROMLONG((pMD->Back)->id));
  852.                 else                    /* This is the complete first item of the linked
  853.                                            list, so insert at the end */
  854.                     SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMD), MPFROMLONG(MIT_END));
  855.                 free(pMDNew->PgmTitle); /* Free temporary used structure */
  856.                 free(pMDNew->PgmName);
  857.                 free(pMDNew->PgmDirectory);
  858.                 free(pMDNew->PgmInputs);
  859.                 free(pMDNew);
  860.                 }
  861.             }
  862.         else
  863.             {
  864.             free(pMDNew->PgmTitle);     /* Free temporary MENUDATA structure */
  865.             free(pMDNew->PgmName);
  866.             free(pMDNew->PgmDirectory);
  867.             free(pMDNew->PgmInputs);
  868.             free(pMDNew);
  869.             }
  870.                                         /* Initialize the listbox */
  871.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  872.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  873.             HWND_DESKTOP,
  874.             HWND_DESKTOP,
  875.             CD_DialogProcedure,
  876.             0,
  877.             CDID_CONFIGDIALOG,
  878.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  879.         break;                          /* We never get here because of calling WinDlgBox() */
  880.         }
  881.  
  882. /*                                                                                      *\
  883.  * The user selected to change an item. Thus dismiss the PC/2 Configuration dialog and  *
  884.  * load the Menu or Program Installation dialog. The new session data is entered in a   *
  885.  * STARTSESSION structure named StartSession.                                           *
  886.  * Then reload the PC/2 Configuration dialog again.                                     *
  887. \*                                                                                      */
  888.     case CDID_CHANGEENTRY:              /* Change a Menu or Program configuration selected */
  889.         {
  890.         MENUDATA        *pMD;
  891.         SHORT           sCount;
  892.  
  893.         pMD=pMenuData;                  /* Point to the first element of the linked list
  894.                                            at the current level */
  895.                                         /* Send message to listbox */
  896.         sCount=(SHORT)WinSendDlgItemMsg(
  897.             hwndDlg,                    /* Handle of dialog window */
  898.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  899.             LM_QUERYSELECTION,          /* Query first selected list box item */
  900.             MPFROMSHORT(LIT_FIRST),
  901.             (MPARAM)NULL);
  902.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  903.             return((MRESULT)FALSE);
  904.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  905.                                            item */
  906.             pMD=pMD->Next;
  907.                                         /* Now load the MENUDATA to SESSIONDATA structure
  908.                                            where the manipulations will take effect */
  909.         LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  910.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  911.         if(pMD->Submenu==NULL)          /* It's a Menuitem so call the Program Installation
  912.                                            dialog box */
  913.             {
  914.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  915.                 HWND_DESKTOP,           /* DESKTOP is parent */
  916.                 HWND_DESKTOP,           /* DESKTOP is owner */
  917.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  918.                                            dialog */
  919.                 0,                      /* Ressource is .EXE file */
  920.                 PIID_PROGRAMDIALOG,     /* ID of Program Installation PC/2 dialog */
  921.                 0))                     /* No initialization data */
  922.                 GEN_ERR(hab, hwndFrame, hwndClient);
  923.             }
  924.         else                            /* It's a Submenu so call the Menu Installation
  925.                                            dialog box */
  926.             {
  927.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  928.                 HWND_DESKTOP,           /* DESKTOP is parent */
  929.                 HWND_DESKTOP,           /* DESKTOP is owner */
  930.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  931.                                            dialog */
  932.                 0,                      /* Ressource is .EXE file */
  933.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  934.                 0))                     /* No initialization data */
  935.                 GEN_ERR(hab, hwndFrame, hwndClient);
  936.             }
  937.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  938.                                            the SESSIONDATA structure back to the MENUDATA
  939.                                            structure and save the changes */
  940.             {
  941.             LoadSessionData2MenuData(pMD, &SessionData);
  942.                                         /* Now change the menuitem text to the new one */
  943.             SetPopupMenu(MM_SETITEMTEXT, MPFROMP(pMD), MPFROMLONG(pMD->id));
  944.                                         /* Initialize the listbox */
  945.             WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  946.             }
  947.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  948.             HWND_DESKTOP,
  949.             HWND_DESKTOP,
  950.             CD_DialogProcedure,
  951.             0,
  952.             CDID_CONFIGDIALOG,
  953.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  954.         break;                          /* We never get here because of calling WinDlgBox() */
  955.         }
  956.  
  957. /*                                                                                      *\
  958.  * The user selected to remove an item. If thist item is the only one in the linked     *
  959.  * list or the first item of a submenu set it to empty otherwise free it's ressources   *
  960.  * and remove the entry.                                                                *
  961. \*                                                                                      */
  962.     case CDID_REMOVEENTRY:              /* Remove a item of the PC/2 Configuration selected */
  963.         {
  964.         UCHAR           *pU;
  965.         MENUDATA        *pMD;
  966.         SHORT           sCount;
  967.  
  968.         pMD=pMenuData;                  /* Point to the first element of the linked list
  969.                                            at the current level */
  970.                                         /* Send message to listbox */
  971.         sCount=(SHORT)WinSendDlgItemMsg(
  972.             hwndDlg,                    /* Handle of dialog window */
  973.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  974.             LM_QUERYSELECTION,          /* Query first selected list box item */
  975.             MPFROMSHORT(LIT_FIRST),
  976.             (MPARAM)NULL);
  977.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  978.             return((MRESULT)FALSE);
  979.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  980.                                            item */
  981.             pMD=pMD->Next;
  982.         while(TRUE)
  983.             {
  984.             if((pMD->Back==NULL) && (pMD->Next!=NULL))
  985.                 {                       /* Remove the first item of the complete linked list */
  986.                 if(pMD->Item==ENTRYSUBMENU)
  987.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  988.                     {                   /* If it is an empty Submenu remove it completely */
  989.                                         /* Remove the Submenu and the empty first item
  990.                                            from the Popup-Menu */
  991.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  992.                     free((pMD->Submenu)->PgmTitle);
  993.                     free((pMD->Submenu)->PgmName);
  994.                     free((pMD->Submenu)->PgmDirectory);
  995.                     free((pMD->Submenu)->PgmInputs);
  996.                     free(pMD->Submenu);
  997.                     (pMD->Next)->Back=NULL;
  998.                                         /* Now next element is the first one */
  999.                     pPopupMenu=pMD->Next;
  1000.                     pMenuData=pMD->Next;
  1001.                     free(pMD->PgmTitle);
  1002.                     free(pMD->PgmName);
  1003.                     free(pMD->PgmDirectory);
  1004.                     free(pMD->PgmInputs);
  1005.                     free(pMD);
  1006.                     break;              /* Ensure we only test once, because each routine
  1007.                                            changes the pointers */
  1008.                     }
  1009.                 if(pMD->Item==ENTRYMENUITEM)
  1010.                     {                   /* If it is an empty Menuitem remove it completly */
  1011.                     (pMD->Next)->Back=NULL;
  1012.                                         /* Now next element is the first one */
  1013.                     pPopupMenu=pMD->Next;
  1014.                     pMenuData=pMD->Next;
  1015.                                         /* Remove the item from the Popup-Menu */
  1016.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1017.                     free(pMD->PgmTitle);
  1018.                     free(pMD->PgmName);
  1019.                     free(pMD->PgmDirectory);
  1020.                     free(pMD->PgmInputs);
  1021.                     free(pMD);
  1022.                     break;              /* Ensure we only test once, because each routine
  1023.                                            changes the pointers */
  1024.                     }
  1025.                 }
  1026.             if((pMD->Back==NULL) && (pMD->Next==NULL))
  1027.                 {                       /* If it is the one and only item of the linked list
  1028.                                            set it to empty */
  1029.                 if(pMD->Item==ENTRYSUBMENU)
  1030.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  1031.                     {                   /* If it is an empty Submenu remove the empty
  1032.                                            item completely */
  1033.                                         /* Remove the item from the Popup-Menu */
  1034.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1035.                     free((pMD->Submenu)->PgmTitle);
  1036.                     free((pMD->Submenu)->PgmName);
  1037.                     free((pMD->Submenu)->PgmDirectory);
  1038.                     free((pMD->Submenu)->PgmInputs);
  1039.                     free(pMD->Submenu);
  1040.                     free(pMD->PgmTitle);
  1041.                     strcpy(pU=malloc(strlen("")+1), "");
  1042.                     pMD->PgmTitle=pU;
  1043.                     free(pMD->PgmName);
  1044.                     strcpy(pU=malloc(strlen("")+1), "");
  1045.                     pMD->PgmName=pU;
  1046.                     free(pMD->PgmDirectory);
  1047.                     strcpy(pU=malloc(strlen("")+1), "");
  1048.                     pMD->PgmDirectory=pU;
  1049.                     free(pMD->PgmInputs);
  1050.                     strcpy(pU=malloc(strlen("")+1), "");
  1051.                     pMD->PgmInputs=pU;
  1052.                     pMD->Item=ENTRYEMPTY;
  1053.                     pMD->Back=NULL;
  1054.                     pMD->Submenu=NULL;
  1055.                     pMD->Next=NULL;
  1056.                     break;              /* Ensure we only test once, because each routine
  1057.                                            changes the pointers */
  1058.                     }
  1059.                 if(pMD->Item==ENTRYMENUITEM)
  1060.                     {                   /* If it is a Menuitem set it to empty */
  1061.                                         /* Remove the item from the Popup-Menu */
  1062.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1063.                     strcpy(pU=malloc(strlen("")+1), "");
  1064.                     pMD->PgmTitle=pU;
  1065.                     free(pMD->PgmName);
  1066.                     strcpy(pU=malloc(strlen("")+1), "");
  1067.                     pMD->PgmName=pU;
  1068.                     free(pMD->PgmDirectory);
  1069.                     strcpy(pU=malloc(strlen("")+1), "");
  1070.                     pMD->PgmDirectory=pU;
  1071.                     free(pMD->PgmInputs);
  1072.                     strcpy(pU=malloc(strlen("")+1), "");
  1073.                     pMD->PgmInputs=pU;
  1074.                     pMD->Item=ENTRYEMPTY;
  1075.                     pMD->Back=NULL;
  1076.                     pMD->Submenu=NULL;
  1077.                     pMD->Next=NULL;
  1078.                     break;              /* Ensure we only test once, because each routine
  1079.                                            changes the pointers */
  1080.                     }
  1081.                 }
  1082.             if(pMD->Back!=NULL)
  1083.                 {                       /* It is any item of more than one item and not
  1084.                                            the first one */
  1085.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Submenu==NULL) && (pMD->Next==NULL))
  1086.                 {                       /* If it is the first item of a Submenu not followed
  1087.                                            by any item, set it to empty */
  1088.                                         /* Remove the item from the Popup-Menu */
  1089.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1090.                     strcpy(pU=malloc(strlen("")+1), "");
  1091.                     pMD->PgmTitle=pU;
  1092.                     free(pMD->PgmName);
  1093.                     strcpy(pU=malloc(strlen("")+1), "");
  1094.                     pMD->PgmName=pU;
  1095.                     free(pMD->PgmDirectory);
  1096.                     strcpy(pU=malloc(strlen("")+1), "");
  1097.                     pMD->PgmDirectory=pU;
  1098.                     free(pMD->PgmInputs);
  1099.                     strcpy(pU=malloc(strlen("")+1), "");
  1100.                     pMD->Item=ENTRYEMPTY;
  1101.                     break;              /* Ensure we only test once, because each routine
  1102.                                            changes the pointers */
  1103.                     }
  1104.                 if(pMD->Item==ENTRYSUBMENU)
  1105.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  1106.                     {                   /* If it is an empty Submenu so also remove the
  1107.                                            first item in the Submenu */
  1108.                                         /* Remove the Submenu and the empty first item
  1109.                                            from the Popup-Menu */
  1110.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1111.                     free((pMD->Submenu)->PgmTitle);
  1112.                     free((pMD->Submenu)->PgmName);
  1113.                     free((pMD->Submenu)->PgmDirectory);
  1114.                     free((pMD->Submenu)->PgmInputs);
  1115.                     free(pMD->Submenu);
  1116.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1117.                         {               /* If the previous item is a Submenu, this item is
  1118.                                            the first item of it. If none item follows, set
  1119.                                            this item to empty */
  1120.                         strcpy(pU=malloc(strlen("")+1), "");
  1121.                         pMD->PgmTitle=pU;
  1122.                         free(pMD->PgmName);
  1123.                         strcpy(pU=malloc(strlen("")+1), "");
  1124.                         pMD->PgmName=pU;
  1125.                         free(pMD->PgmDirectory);
  1126.                         strcpy(pU=malloc(strlen("")+1), "");
  1127.                         pMD->PgmDirectory=pU;
  1128.                         free(pMD->PgmInputs);
  1129.                         strcpy(pU=malloc(strlen("")+1), "");
  1130.                         pMD->Item=ENTRYEMPTY;
  1131.                         pMD->Submenu=NULL;
  1132.                         pMD->Next=NULL;
  1133.                         break;          /* Ensure we only test once, because each routine
  1134.                                            changes the pointers */
  1135.                         }
  1136.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1137.                         {               /* If the previous item is a Submenu, this item ist
  1138.                                            the first item of it. If one item follows adjust
  1139.                                            the pointer to the current level of items */
  1140.                         pMenuData=pMD->Next;
  1141.                         (pMD->Back)->Submenu=pMD->Next;
  1142.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1143.                         free(pMD->PgmTitle);
  1144.                         free(pMD->PgmName);
  1145.                         free(pMD->PgmDirectory);
  1146.                         free(pMD->PgmInputs);
  1147.                         free(pMD);
  1148.                         break;          /* Ensure we only test once, because each routine
  1149.                                            changes the pointers */
  1150.                         }
  1151.                     if((pMD->Back)->Submenu!=pMD)
  1152.                         {               /* If this item isn't the first item of a Submenu */
  1153.                         (pMD->Back)->Next=pMD->Next;
  1154.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1155.                         free(pMD->PgmTitle);
  1156.                         free(pMD->PgmName);
  1157.                         free(pMD->PgmDirectory);
  1158.                         free(pMD->PgmInputs);
  1159.                         free(pMD);
  1160.                         break;          /* Ensure we only test once, because each routine
  1161.                                            changes the pointers */
  1162.                         }
  1163.                     }
  1164.                 if(pMD->Item==ENTRYMENUITEM)
  1165.                     {                   /* If it is a Menuitem, just remove it completly */
  1166.                                         /* Remove the item from the Popup-Menu */
  1167.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1168.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1169.                         {               /* If the previous item is a Submenu, this item is
  1170.                                            the first item of it. If none item follows, set
  1171.                                            this item to empty */
  1172.                         strcpy(pU=malloc(strlen("")+1), "");
  1173.                         pMD->PgmTitle=pU;
  1174.                         free(pMD->PgmName);
  1175.                         strcpy(pU=malloc(strlen("")+1), "");
  1176.                         pMD->PgmName=pU;
  1177.                         free(pMD->PgmDirectory);
  1178.                         strcpy(pU=malloc(strlen("")+1), "");
  1179.                         pMD->PgmDirectory=pU;
  1180.                         free(pMD->PgmInputs);
  1181.                         strcpy(pU=malloc(strlen("")+1), "");
  1182.                         pMD->Item=ENTRYEMPTY;
  1183.                         pMD->Submenu=NULL;
  1184.                         pMD->Next=NULL;
  1185.                         break;          /* Ensure we only test once, because each routine
  1186.                                            changes the pointers */
  1187.                         }
  1188.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1189.                         {               /* If the previous item is a Submenu, this item ist
  1190.                                            the first item of it. If one item follows adjust
  1191.                                            the pointer to the current level of items */
  1192.                         pMenuData=pMD->Next;
  1193.                         (pMD->Back)->Submenu=pMD->Next;
  1194.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1195.                         free(pMD->PgmTitle);
  1196.                         free(pMD->PgmName);
  1197.                         free(pMD->PgmDirectory);
  1198.                         free(pMD->PgmInputs);
  1199.                         free(pMD);
  1200.                         break;          /* Ensure we only test once, because each routine
  1201.                                            changes the pointers */
  1202.                         }
  1203.                     if((pMD->Back)->Submenu!=pMD)
  1204.                         {               /* If this item isn't the first item of a Submenu */
  1205.                         (pMD->Back)->Next=pMD->Next;
  1206.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1207.                         free(pMD->PgmTitle);
  1208.                         free(pMD->PgmName);
  1209.                         free(pMD->PgmDirectory);
  1210.                         free(pMD->PgmInputs);
  1211.                         free(pMD);
  1212.                         break;          /* Ensure we only test once, because each routine
  1213.                                            changes the pointers */
  1214.                         }
  1215.                     }
  1216.                 }
  1217.             break;                      /* If we come here, we're trying to remove an not
  1218.                                            empty Submenu, but we also must exit the
  1219.                                            endless loop */
  1220.             }
  1221.                                         /* Initialize the listbox */
  1222.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  1223.         return((MRESULT)FALSE);         /* We have done everything */
  1224.         }
  1225.  
  1226. /*                                                                                      *\
  1227.  * The user selected to resort the current level of the menuentries. Load the dialog    *
  1228.  * and let the user resort the linked list of menues pointed to by pMenuData and to     *
  1229.  * resort the menuentries of the Popup-Menu.                                            *
  1230. \*                                                                                      */
  1231.     case CDID_RESORT:                   /* Load the resort dialog */
  1232.         {
  1233.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  1234.         if(!WinDlgBox(                  /* Start Resort dialog box */
  1235.             HWND_DESKTOP,               /* DESKTOP is parent */
  1236.             HWND_DESKTOP,               /* DESKTOP is owner */
  1237.             RD_DialogProcedure,         /* Dialog procedure of Program Installation
  1238.                                            dialog */
  1239.             0,                          /* Ressource is .EXE file */
  1240.             RDID_RESORTDIALOG,          /* ID of Program Installation PC/2 dialog */
  1241.             0))                         /* No initialization data */
  1242.             GEN_ERR(hab, hwndFrame, hwndClient);
  1243.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  1244.             HWND_DESKTOP,
  1245.             HWND_DESKTOP,
  1246.             CD_DialogProcedure,
  1247.             0,
  1248.             CDID_CONFIGDIALOG,
  1249.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  1250.         }
  1251.         break;
  1252.  
  1253.     case DID_OK:                        /* Enter key pressed */
  1254.                                         /* Save the changes */
  1255.         WinSendMsg(hwndDlg, WM_SAVEPOPUPMENU, NULL, NULL);
  1256.         DialogResult=DID_OK;            /* Dialog terminated with DID_OK */
  1257.         break;
  1258.  
  1259.     case DID_CANCEL:                    /* Escape or Cancel pressed */
  1260.         DialogResult=DID_CANCEL;        /* Dialog terminated with DID_CANCEL */
  1261.         break;
  1262.  
  1263.     default:
  1264.         return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1265.     }
  1266.     WinDismissDlg(hwndDlg, TRUE);       /* Clear up dialog */
  1267.     break;
  1268.  
  1269. default:                                /* Default window procedure must be called */
  1270.     return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1271. }
  1272. return((MRESULT)FALSE);                 /* We have handled the message */
  1273. }
  1274.  
  1275.  
  1276.